/*
 * @Author: CBH37
 * @Date: 2023-01-17 17:07:16
 * @Description: 主程序头文件
 */
#pragma once

#include <iostream>
#include <string>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <memory>
#include <sstream>

#include "nbd.hpp"
#include "nas.hpp"
#include "nvm.hpp"
#include "global.hpp"
#include "nlc_def.hpp"

/************ Tokenizer 部分 ************/
size_t index = 0;
std::string src;

enum Token {
    tok_num,
    tok_str,
    tok_ident,
    tok_other,  // 可能为连接符、运算符或关键字
    tok_eof,
};

int token = - 1;
std::string tokVal = "";

// 连接符
std::set<std::string> connectSymbolTable = {
    ":", "=", ";", ",", ".",
    "(", ")", "{", "}", "[", "]", "<", ">",
};

// 为了防止一发而牵全身且`JS`作为一种成熟的语言该有的运算符应有尽有，所以直接使用`JS`现成的优先级
// 运算符优先级参考：https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
std::map<std::string, int> binaryOpTable = {
    { "**" , 14 },
    { "*" , 13 }, { "/" , 13 }, { "%" , 13 },
    { "+" , 12 }, { "-" , 12 },

    { ">" , 10 }, { ">=" , 10 }, { "<" , 10 }, { "<=" , 10 },
    { "==" , 9 }, { "!=" , 9 },
    { "&&" , 5 }, { "||" , 4 },
};

// 算术运算符
std::set<std::string> mathOpTable = {
    "**", "+", "-", "*", "/", "%",
};

// 一元运算符人人平等所以不需要优先级，直接使用`set`即可
std::set<std::string> unaryOpTable = {
    "!", "+", "-",
};

std::set<std::string> keywordTable = {
    "let", "const",
    "for", "while", "loop", "break", "continue",
    "if", "else", "elif", "match",
    "class", "new",
    "fn", "return",
    "import", "extern", "action",
    "true", "false",
};
void getToken();

/************ Parser 部分 ************/
// 所有组成`AST`的类的集体虚拟基类
class BaseAST {
public:
    virtual void codegen() = 0;  // 代码生成
};

/* 符号表部分 */
// 不同性质的类型：包括`nl`内建类型和用户自建类型
enum TypeType {
    BUILDIN_TYPE,
    CLASS_TYPE,
};

std::map<std::string, TypeType> typeTable = {
    { "number", BUILDIN_TYPE }, { "int", BUILDIN_TYPE }, { "bool", BUILDIN_TYPE },
    { "string", BUILDIN_TYPE }, { "void", BUILDIN_TYPE },
    { "list", BUILDIN_TYPE}, { "map", BUILDIN_TYPE },
    { "fn", BUILDIN_TYPE }, { "efn", BUILDIN_TYPE },    // 外部函数
    { "any", BUILDIN_TYPE }, { "uncertain", BUILDIN_TYPE }, // 不确定类型
};

class TypeMessage {
public:
    bool isExtern = false;

    std::string name;
    std::vector<std::shared_ptr<TypeMessage>> args;

    TypeMessage() {}
    TypeMessage(std::string _name, bool _isExtern = false, std::vector<std::shared_ptr<TypeMessage>> _args = {})
        : name(_name), isExtern(_isExtern), args(_args) {}
};

// 实现符号表
enum SymbolState {
    symbol_local,
    symbol_global,
    symbol_member,  // 类成员
};
class SymbolMessage {
public:
    SymbolState state;
    bool isConst;
    bool isAssign;  // 是否赋值过，用于解决常量没有赋值就无法修改的情况
    std::shared_ptr<TypeMessage> type;
    
    SymbolMessage() {}
    SymbolMessage(std::shared_ptr<TypeMessage> _type, SymbolState _state, bool _isConst = false, bool _isAssign = true)
        : type(_type), state(_state), isConst(_isConst), isAssign(_isAssign) {}
};

// 程序中越早开始的符号越晚失效，为了实现这种类似栈的特性，管理和存储符号的符号表使用`std::vector`来模拟
std::vector<std::map<std::string, std::shared_ptr<SymbolMessage>>> symbolTable(1);
void insertSymbol(std::string symbol, std::shared_ptr<SymbolMessage> message);
std::shared_ptr<SymbolMessage> getSymbol(std::string symbol);

/* Expr 部分 */
class NumAST : public BaseAST {
    NlcFile::Num num;

public:
    static std::shared_ptr<NumAST> parser();
    void codegen() override;

    NumAST(NlcFile::Num _num) : num(_num) {}
};

class StringAST : public BaseAST {
    std::string string;

public:
    static std::shared_ptr<StringAST> parser();
    void codegen() override;
    StringAST(std::string& _string) : string(_string) {}
};

class IdentAST : public BaseAST {
    std::string ident;
    std::shared_ptr<BaseAST> value; // ident = value
    SymbolState state;

public:
    void codegen() override;
    IdentAST(std::string& _ident, SymbolState _state, std::shared_ptr<BaseAST> _value = nullptr)
        : ident(_ident), state(_state), value(_value) {}
};

class UnaryExprAST : public BaseAST {
    std::string op;
    std::shared_ptr<BaseAST> value;

public:
    static std::shared_ptr<UnaryExprAST> parser();
    void codegen() override;
    UnaryExprAST(std::string& _op, std::shared_ptr<BaseAST> _value) : op(_op), value(_value) {}
};

class BinaryExprAST : public BaseAST {
    std::string op;
    std::shared_ptr<BaseAST> left;
    std::shared_ptr<BaseAST> right;

public:
    static std::shared_ptr<BaseAST> parser();
    void codegen() override;
    BinaryExprAST(std::string& _op, std::shared_ptr<BaseAST> _left, std::shared_ptr<BaseAST> _right)
        : op(_op), left(_left), right(_right) {}
};

class ListAST : public BaseAST {
    std::vector<std::shared_ptr<BaseAST>> items;

public:
    static std::shared_ptr<ListAST> parser();
    void codegen() override;
    ListAST(std::vector<std::shared_ptr<BaseAST>> _items = {}) : items(_items) {}
};

class MapAST : public BaseAST {
    // 为了解析方便，一解析一存储，将`key`和`value`分为两部分存储
    std::vector<std::shared_ptr<BaseAST>> keys;
    std::vector<std::shared_ptr<BaseAST>> values;

public:
    static std::shared_ptr<MapAST> parser();
    void codegen() override;
    MapAST(std::vector<std::shared_ptr<BaseAST>> _keys = {}, std::vector<std::shared_ptr<BaseAST>> _values = {})
        : keys(_keys), values(_values) {}
};

class AccessAST : public BaseAST {
    std::string accessType; // 访问对象类型
    std::shared_ptr<BaseAST> object;    // 被访问对象
    std::shared_ptr<BaseAST> key;   // 访问表达式
    std::shared_ptr<BaseAST> value; // object[key] = value（当遇到`=`时）

public:
    void codegen() override;
    AccessAST(std::string& _accessType, std::shared_ptr<BaseAST> _object, std::shared_ptr<BaseAST> _key, std::shared_ptr<BaseAST> _value = nullptr)
        : accessType(_accessType), object(_object), key(_key), value(_value) {}
};

class CallAST : public BaseAST {
    bool isExtern;
    std::shared_ptr<BaseAST> object;
    std::vector<std::shared_ptr<BaseAST>> args;

public:
    void codegen() override;
    CallAST(std::shared_ptr<BaseAST> _object, std::vector<std::shared_ptr<BaseAST>> _args, bool _isExtern)
        : object(_object), args(_args), isExtern(_isExtern) {}
};

// map/ list : actionName   操作`map`/ `list`
class ActionAST : public BaseAST {
    std::string type;   // 被操作者类型
    std::shared_ptr<BaseAST> object;    // 操作对象
    std::string actionName;   // 操作名
    std::vector<std::shared_ptr<BaseAST>> args;

public:
    void codegen() override;
    ActionAST(std::string& _type, std::shared_ptr<BaseAST> _object, std::string& _actionName, std::vector<std::shared_ptr<BaseAST>> _args)
        : type(_type), object(_object), actionName(_actionName), args(_args) {}
};

// 复杂类型；需要类型参数的类型
std::set<std::string> complexTypes = {
    "map", "list", "fn", "efn",
};

std::shared_ptr<TypeMessage> type;  // 记录当前所处理的值或表达式的类型，用于类型推导
std::shared_ptr<TypeMessage> parseTypeExpr();   // 解析类型表达式
bool matchType(std::shared_ptr<TypeMessage> expectType, std::shared_ptr<TypeMessage> inputType = type);   // 判断表达式类型与期望类型是否匹配
std::shared_ptr<BaseAST> parseValue();  // 解析可用于二元表达式解析的值
#define expr()  BinaryExprAST::parser()
bool isGlobal(); 

// 定义变量和常量
class DefAST : public BaseAST {
    bool isConst;
    SymbolState state;
    std::string name;
    std::shared_ptr<BaseAST> value;

public:
    static std::shared_ptr<DefAST> parser();
    void codegen() override;
    inline std::string getName() { return name; }
    DefAST(std::string& _name, bool _isConst, SymbolState _state) : name(_name), isConst(_isConst), state(_state) {}
    DefAST(std::string& _name, std::shared_ptr<BaseAST> _value, bool _isConst, SymbolState _state) : name(_name), value(_value), isConst(_isConst), state(_state) {}
};

class Prototype {
public:
    std::string fnName;
    std::vector<std::string> argNames;
    std::vector<std::shared_ptr<TypeMessage>> argTypes;
};

Prototype parsePrototype();  // 解析原型并将其加入函数表

std::vector<std::shared_ptr<BaseAST>> parseSubpart();   // 解析子部分（如块或`if`/ `for`等所作用的一条语句）

class FnAST : public BaseAST {
    bool isInClass;
    Prototype prototype;
    std::vector<std::shared_ptr<BaseAST>> body;

public:
    static std::shared_ptr<FnAST> parser();
    void codegen() override;
    inline std::string getName() { return prototype.fnName; }
    FnAST(Prototype _prototype, std::vector<std::shared_ptr<BaseAST>> _body, bool _isInClass = false) : prototype(_prototype), body(_body), isInClass(_isInClass) {}
};

std::shared_ptr<Prototype> currentFn;   // 当前函数的原型，用于`return`语句的类型判断
class ReturnAST : public BaseAST {
    std::shared_ptr<BaseAST> value;

public:
    static std::shared_ptr<ReturnAST> parser();
    void codegen() override;
    ReturnAST(std::shared_ptr<BaseAST> _value) : value(_value) {}
};

void parseExtern(); // 由于`extern`语句本身不会生成什么代码，所以没必要将其记录在`AST`中，直接解析即可

class ImportAST : public BaseAST {
    std::shared_ptr<BaseAST> name;  // 引入模块名

public:
    static std::shared_ptr<ImportAST> parser();
    void codegen() override;
    ImportAST(std::shared_ptr<BaseAST> _name) : name(_name) {}
};

// 空语句，用于应付那些不生成代码的语句生成代码
class NopAST : public BaseAST {
public:
    void codegen() override;
};

using Member = std::pair<std::shared_ptr<TypeMessage>, std::shared_ptr<BaseAST>>;    // <menmberType, member>*
std::map<std::string, std::map<std::string, Member>> classTable;    // { className : members }*
bool isClassMember = false;
void parseClass();
class NewAST : public BaseAST {
    std::string className;
    std::vector<std::shared_ptr<BaseAST>> args;

public:
    static std::shared_ptr<NewAST> parser();
    void codegen() override;
};

// { actionType : { actionName : types(actionArgTypes & actionReturnType) }}
std::map<std::string, std::map<std::string, std::vector<std::shared_ptr<TypeMessage>>>> actions;
void parseActionDef();

std::vector<std::shared_ptr<BaseAST>> program;  // `AST`的根即处理的整个程序
std::shared_ptr<BaseAST> parseStatement();
std::vector<std::shared_ptr<BaseAST>> parser();

/************ 代码生成部分 ************/
Nbd builder;
void codegenSubpart(std::vector<std::shared_ptr<BaseAST>> statements);
void codegen();